#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <sys/ipc.h>
#include <sys/sem.h>

#define N		20
#define	FLNAME	"/tmp/out"
#define BUFSIZE	64

static int semid;

static void P(void);
static void V(void);
static void rw_file(void);

int main(void)
{
	FILE *fp = NULL;
	int i;
	pid_t pid;

	// 信号量集中只有一个成员 数组中一个元素
	semid = semget(IPC_PRIVATE, 1, IPC_CREAT | IPC_EXCL | 0600);
	if(-1 == semid) {
		perror("semgget()");
		exit(1);
	}
	// 初始化信号的个数, 将数组中下标为0的成员初始化为1
	semctl(semid, 0, SETVAL, 1);

	fp = fopen(FLNAME, "w");
	if (NULL == fp) {
		perror("fopen()");
		exit(1);
	}
	fputs("0", fp);
	fclose(fp);

	for (i = 0; i < N; i++) {
		pid = fork();
		if (-1 == pid) {
			perror("fork()");
			exit(1);
		}
		if (0 == pid) {
			rw_file();	
			exit(0);
		}
	}
	
	for (i = 0; i < N; i++) {
		wait(NULL);
	}

	semctl(semid, 0, IPC_RMID, NULL);

	return 0;
}

static void rw_file(void)
{
	FILE *fp = NULL;
	char buf[BUFSIZE] = {};

	// sleep(1);
	
	fp = fopen(FLNAME, "r+"); 
	if (NULL == fp) {
		perror("fopen()");
		return;
	}
	/*
	 	多进程之间竞争
	 */
	// 取信号
	P();
	fgets(buf, BUFSIZE, fp);
	// sleep(1);
	rewind(fp);
	fprintf(fp, "%d", atoi(buf) + 1);
	fclose(fp);
	// 还信号
	V();
}

static void P(void)
{
	struct sembuf sop;

	sop.sem_num = 0;// 数组下标
	sop.sem_op = -1; // 取走一个信号
	sop.sem_flg = 0; // 没有特殊要求
	if (-1 == semop(semid, &sop, 1)) {
		perror("semop()");
		return;
	}
}

static void V(void)
{
	struct sembuf sop;

	sop.sem_num = 0;// 数组下标
	sop.sem_op = 1; // 还一个信号
	sop.sem_flg = 0; // 没有特殊要求
	if (-1 == semop(semid, &sop, 1)) {
		perror("semop()");
		return;
	}
}





